using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using SchoolApp.Models;
using SchoolApp.Msgs;

namespace SchoolApp.ViewModels;

public class LoginViewModel : ViewModelBase, INotifyDataErrorInfo
{
    private ILogger<LoginViewModel> _logger;
    private IFreeSql _freeSql;

    public LoginViewModel()
    {
        if (!Design.IsDesignMode)
            return;
        OperatorCode = "admin";
        OperatorPwd = "admin";
    }

    public LoginViewModel(ILogger<LoginViewModel> logger, IFreeSql freeSql)
    {
        _logger = logger;
        _freeSql = freeSql;
        var opAdmin = _freeSql.Select<Operator>().Where(o => o.Code == "admin").First();
        if (opAdmin == null)
        {
            opAdmin = new Operator()
            {
                Code = "admin",
                Name = "admin",
                CreateOperatorCode = "admin",
                CreateOperatorName = "admin",
                CreateTime = DateTime.Now
            };
            var rowCount = _freeSql.Insert(opAdmin).ExecuteAffrows();
            _logger.LogInformation($"新增{rowCount}条Operator数据");
        }
        else if (opAdmin.IsDeleted)
        {
            opAdmin.IsDeleted = false;
            opAdmin.UpdateOperatorCode = "admin";
            opAdmin.UpdateOperatorName = "admin";
            opAdmin.UpdateTime = DateTime.Now;
            var rowCount = _freeSql.Update<Operator>(opAdmin).ExecuteAffrows();
            _logger.LogInformation($"更新{rowCount}条Operator数据");
        }
    }

    #region 属性

    private string _operatorCode;

    public string OperatorCode
    {
        get => _operatorCode;
        set
        {
            SetProperty(ref _operatorCode, value);
            ValidateOperatorCode();
        }
    }

    private string _operatorPwd;

    public string OperatorPwd
    {
        get => _operatorPwd;
        set => SetProperty(ref _operatorPwd, value);
    }

    #endregion

    #region 命令

    private RelayCommand _loginCmd;

    public RelayCommand LoginCmd =>
        _loginCmd ??= new RelayCommand(ExecuteLoginCmd, CanExecuteLoginCmd);

    private void ExecuteLoginCmd()
    {
        ValidateOperatorCode();
        if (HasErrors)
            return;

        if (LoginOk())
        {
            // 发送消息
            // MessageBus.Current.SendMessage(new LoginMsg { OperatorCode = OperatorCode });
            WeakReferenceMessenger.Default.Send(new LoginMsg{ OperatorCode = OperatorCode });
        }
        else
        {
            // MessageBus.Current.SendMessage(new ErrorMsg { Data = "帐号或密码错误" });
            WeakReferenceMessenger.Default.Send(new ErrorMsg { Data = "帐号或密码错误" });
        }
    }

    private bool CanExecuteLoginCmd()
    {
        return !HasErrors;
    }

    #endregion

    #region 方法

    private void ValidateOperatorCode()
    {
        _errors.Remove(nameof(OperatorCode));
        var errors = new List<string>();

        if (string.IsNullOrWhiteSpace(OperatorCode))
            errors.Add("账号不能为空");

        if (errors.Any())
            _errors.Add(nameof(OperatorCode), errors);

        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(OperatorCode)));
    }

    private bool LoginOk()
    {
        var iQuery = _freeSql.Select<Operator>().Where(o => !o.IsDeleted);
        iQuery = iQuery.Where(o => o.Code == OperatorCode);
        var _operator = iQuery.First();
        if (_operator == null)
            return false;
        if (string.IsNullOrEmpty(OperatorPwd))
        {
            if (string.IsNullOrEmpty(_operator.Pwd))
            {
                RecordLoginInfo(_operator);
                return true;
            }
        }
        else
        {
            if (_operator.Pwd == OperatorPwd)
            {
                RecordLoginInfo(_operator);
                return true;
            }
        }

        return false;
    }

    private void RecordLoginInfo(Operator op)
    {
        Common.LoginOperator = new OperatorInfo()
        {
            Code = op.Code,
            Name = op.Name,
            LoginTime = DateTime.Now
        };
    }

    #endregion

    #region INotifyDataErrorInfo 实现

    private readonly Dictionary<string, List<string>> _errors = new();

    public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;
    public bool HasErrors => _errors.Any();

    public IEnumerable GetErrors(string? propertyName) =>
        propertyName != null && _errors.TryGetValue(propertyName, out var errors)
            ? errors
            : Enumerable.Empty<string>();

    #endregion
}